home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 60 / IOPROG_60.ISO / soft / c++ / gsl-1.1.1-setup.exe / {app} / src / linalg / cholesky.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-08-22  |  5.5 KB  |  219 lines

  1. /* Cholesky Decomposition
  2.  *
  3.  * Copyright (C) 2000  Thomas Walter
  4.  *
  5.  * 3 May 2000: Modified for GSL by Brian Gough
  6.  *
  7.  * This is free software; you can redistribute it and/or modify it
  8.  * under the terms of the GNU General Public License as published by the
  9.  * Free Software Foundation; either version 2, or (at your option) any
  10.  * later version.
  11.  *
  12.  * This source is distributed in the hope that it will be useful, but WITHOUT
  13.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15.  * for more details.
  16.  */
  17.  
  18. /*
  19.  * Cholesky decomposition of a symmetrix positive definite matrix.
  20.  * This is useful to solve the matrix arising in
  21.  *    periodic cubic splines
  22.  *    approximating splines
  23.  *
  24.  * This algorthm does:
  25.  *   A = L * L'
  26.  * with
  27.  *   L  := lower left triangle matrix
  28.  *   L' := the transposed form of L.
  29.  *
  30.  */
  31.  
  32. #include <config.h>
  33.  
  34. #include <gsl/gsl_math.h>
  35. #include <gsl/gsl_errno.h>
  36. #include <gsl/gsl_vector.h>
  37. #include <gsl/gsl_matrix.h>
  38. #include <gsl/gsl_blas.h>
  39. #include <gsl/gsl_linalg.h>
  40.  
  41. int
  42. gsl_linalg_cholesky_decomp (gsl_matrix * A)
  43. {
  44.   const size_t M = A->size1;
  45.   const size_t N = A->size2;
  46.  
  47.   if (M != N)
  48.     {
  49.       GSL_ERROR("cholesky decomposition requires square matrix", GSL_ENOTSQR);
  50.     }
  51.   else
  52.     {
  53.       size_t i,j,k;
  54.       int status = 0;
  55.  
  56.       /* Do the first 2 rows explicitly.  It is simple, and faster.  And
  57.        * one can return if the matrix has only 1 or 2 rows.  
  58.        */
  59.  
  60.       double A_00 = gsl_matrix_get (A, 0, 0);
  61.       
  62.       double L_00 = sqrt(A_00);
  63.       
  64.       if (A_00 <= 0)
  65.         {
  66.           status = GSL_EDOM ;
  67.         }
  68.  
  69.       gsl_matrix_set (A, 0, 0, L_00);
  70.   
  71.       if (M > 1)
  72.         {
  73.           double A_10 = gsl_matrix_get (A, 1, 0);
  74.           double A_11 = gsl_matrix_get (A, 1, 1);
  75.           
  76.           double L_10 = A_10 / L_00;
  77.           double diag = A_11 - L_10 * L_10;
  78.           double L_11 = sqrt(diag);
  79.           
  80.           if (diag <= 0)
  81.             {
  82.               status = GSL_EDOM;
  83.             }
  84.  
  85.           gsl_matrix_set (A, 1, 0, L_10);        
  86.           gsl_matrix_set (A, 1, 1, L_11);
  87.         }
  88.       
  89.       for (k = 2; k < M; k++)
  90.         {
  91.           double A_kk = gsl_matrix_get (A, k, k);
  92.           
  93.           for (i = 0; i < k; i++)
  94.             {
  95.               double sum = 0;
  96.  
  97.               double A_ki = gsl_matrix_get (A, k, i);
  98.               double A_ii = gsl_matrix_get (A, i, i);
  99.  
  100.               gsl_vector_view ci = gsl_matrix_row (A, i);
  101.               gsl_vector_view ck = gsl_matrix_row (A, k);
  102.  
  103.               if (i > 0) {
  104.                 gsl_vector_view di = gsl_vector_subvector(&ci.vector, 0, i);
  105.                 gsl_vector_view dk = gsl_vector_subvector(&ck.vector, 0, i);
  106.                 
  107.                 gsl_blas_ddot (&di.vector, &dk.vector, &sum);
  108.               }
  109.  
  110.               A_ki = (A_ki - sum) / A_ii;
  111.               gsl_matrix_set (A, k, i, A_ki);
  112.             } 
  113.  
  114.           {
  115.             gsl_vector_view ck = gsl_matrix_row (A, k);
  116.             gsl_vector_view dk = gsl_vector_subvector (&ck.vector, 0, k);
  117.             
  118.             double sum = gsl_blas_dnrm2 (&dk.vector);
  119.             double diag = A_kk - sum * sum;
  120.  
  121.             double L_kk = sqrt(diag);
  122.             
  123.             if (diag <= 0)
  124.               {
  125.                 status = GSL_EDOM;
  126.               }
  127.             
  128.             gsl_matrix_set (A, k, k, L_kk);
  129.           }
  130.         }
  131.  
  132.       /* Now copy the transposed lower triangle to the upper triangle,
  133.        * the diagonal is common.  
  134.        */
  135.       
  136.       for (i = 1; i < M; i++)
  137.         {
  138.           for (j = 0; j < i; j++)
  139.             {
  140.               double A_ij = gsl_matrix_get (A, i, j);
  141.               gsl_matrix_set (A, j, i, A_ij);
  142.             }
  143.         } 
  144.       
  145.       if (status == GSL_EDOM)
  146.         {
  147.           GSL_ERROR ("matrix must be positive definite", GSL_EDOM);
  148.         }
  149.       
  150.       return GSL_SUCCESS;
  151.     }
  152. }
  153.  
  154.  
  155. int
  156. gsl_linalg_cholesky_solve (const gsl_matrix * LLT,
  157.                            const gsl_vector * b,
  158.                            gsl_vector * x)
  159. {
  160.   if (LLT->size1 != LLT->size2)
  161.     {
  162.       GSL_ERROR ("cholesky matrix must be square", GSL_ENOTSQR);
  163.     }
  164.   else if (LLT->size1 != b->size)
  165.     {
  166.       GSL_ERROR ("matrix size must match b size", GSL_EBADLEN);
  167.     }
  168.   else if (LLT->size2 != x->size)
  169.     {
  170.       GSL_ERROR ("matrix size must match solution size", GSL_EBADLEN);
  171.     }
  172.   else
  173.     {
  174.       /* Copy x <- b */
  175.  
  176.       gsl_vector_memcpy (x, b);
  177.  
  178.       /* Solve for c using forward-substitution, L c = b */
  179.  
  180.       gsl_blas_dtrsv (CblasLower, CblasNoTrans, CblasNonUnit, LLT, x);
  181.  
  182.       /* Perform back-substitution, U x = c */
  183.  
  184.       gsl_blas_dtrsv (CblasUpper, CblasNoTrans, CblasNonUnit, LLT, x);
  185.  
  186.  
  187.       return GSL_SUCCESS;
  188.     }
  189. }
  190.  
  191. int
  192. gsl_linalg_cholesky_svx (const gsl_matrix * LLT,
  193.                          gsl_vector * x)
  194. {
  195.   if (LLT->size1 != LLT->size2)
  196.     {
  197.       GSL_ERROR ("cholesky matrix must be square", GSL_ENOTSQR);
  198.     }
  199.   else if (LLT->size2 != x->size)
  200.     {
  201.       GSL_ERROR ("matrix size must match solution size", GSL_EBADLEN);
  202.     }
  203.   else
  204.     {
  205.       /* Solve for c using forward-substitution, L c = b */
  206.  
  207.       gsl_blas_dtrsv (CblasLower, CblasNoTrans, CblasNonUnit, LLT, x);
  208.  
  209.       /* Perform back-substitution, U x = c */
  210.  
  211.       gsl_blas_dtrsv (CblasUpper, CblasNoTrans, CblasNonUnit, LLT, x);
  212.  
  213.       return GSL_SUCCESS;
  214.     }
  215. }
  216.  
  217.  
  218.  
  219.